﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Serialization;
using Lipcas.Common.FluentAspects;

namespace Douban.Api.Authorization
{
    public class FileSystemAccessTokenManager : IAccessTokenManager
    {
        private readonly string _tokenFilePath;
        private static KeyValuePair<string, string> _tokenCache;

        static FileSystemAccessTokenManager()
        {
            _tokenCache = default(KeyValuePair<string, string>);
        }

        public FileSystemAccessTokenManager()
        {
            string tokenFileFolder = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "豆Q");

            _tokenFilePath = Path.Combine(tokenFileFolder, "token");

            if (!Directory.Exists(tokenFileFolder))
                Directory.CreateDirectory(tokenFileFolder);
        }

        public void StoreToken(string token, string secret)
        {
            if (string.IsNullOrEmpty(token))
                throw new ArgumentNullException("token");

            if (string.IsNullOrEmpty(secret))
                throw new ArgumentNullException("secret");

            TokenItem tokenItem = new TokenItem
            {
                AccessToken = token,
                AccessTokenSecret = secret
            };

            using(Stream stream = GetFileStream())
            {
                XmlSerializer serializer = new XmlSerializer(typeof (TokenItem));
                serializer.Serialize(stream, tokenItem);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException">If there's no token available</exception>
        public KeyValuePair<string, string> GetToken()
        {
            if (!IsTokenAvailable)
                throw new InvalidOperationException("No access token available");

            if (_tokenCache.Key != null)
                return _tokenCache;

            Stream stream = GetFileStream();

            XmlSerializer serializer = new XmlSerializer(typeof (TokenItem));
            TokenItem tokenItem = (TokenItem)serializer.Deserialize(stream);

            stream.Close();

            _tokenCache = new KeyValuePair<string, string>(tokenItem.AccessToken, tokenItem.AccessTokenSecret);

            return _tokenCache;
        }

        public void Clear()
        {
            if (!IsTokenAvailable) return;

            File.Delete(_tokenFilePath);
            _tokenCache = default(KeyValuePair<string, string>);
        }

        public bool IsTokenAvailable { get { return File.Exists(_tokenFilePath); } }

        private Stream GetFileStream()
        {
            if (!File.Exists(_tokenFilePath))
                return File.Create(_tokenFilePath);

            return File.Open(_tokenFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
        }
    }
}
